
#include "Value.h"
#include <sstream>

std::string Value::error("Error converting!");

Value::operator std::string() const
{
	if(!m_data.size()) return error;
	if(!m_data.front()->m_data) return error;
	if(m_data.front()->m_type != TYPE_STRING) {
		if(m_data.front()->m_type < TYPE_STRING) {
			std::stringstream s;

			switch(m_data.front()->m_type) {
				case TYPE_INT:		
					{
						int32* i = (int32*)m_data.front()->m_data;
						int temp = *i;
						s << temp;
					} break;
				case TYPE_UINT:		
					{
						uint32* i = (uint32*)m_data.front()->m_data;
						unsigned temp = *i;
						s << temp;
					} break;
				case TYPE_CHAR:		
					{
						char* c = (char*)m_data.front()->m_data;
						char temp = *c;
						s << temp;
					} break; 
				default: break;
			}

			return s.str();

		} else return error;
	}
	return *static_cast<std::string*>(m_data.front()->m_data);
}

Value::operator int32() const
{
	if (!m_data.size()) return 0;
	if (!m_data.front()->m_data) return 0;
	if (m_data.front()->m_type != TYPE_INT) {
		return 0;
	}
	return *static_cast<int32*>(m_data.front()->m_data);
}

Value::operator char() const
{
	if (!m_data.size()) return 0;
	if (!m_data.front()->m_data) return 0;
	if (m_data.front()->m_type != TYPE_CHAR) {
		return 0;
	}
	return *static_cast<char*>(m_data.front()->m_data);
}
Value::operator uint32() const
{
	if (!m_data.front()) return 0;
	if (!m_data.front()->m_data) return 0;
	switch (m_data.front()->m_type)
	{
	case TYPE_INT:
	case TYPE_UINT:
	case TYPE_CHAR:
		return *static_cast<uint32*>(m_data.front()->m_data);
	default: return 0;
	}
}

Value::~Value()
{
	Clear();
}

void Value::Clear()
{
	if(m_data.size()) { 
		for (std::list<Data*>::iterator  i = m_data.begin(); i!=m_data.end(); i++) {
			delete *i;
		}
		m_data.clear();
	}
}

bool Value::operator>( const Value& value )
{
	if(value.size() != this->size()) 
		return false; 
	if(value.GetType() != this->GetType()) 
		return false;
	switch(this->GetType()) 
	{
	case TYPE_INT:		return int32(*this) > int32(value); 
	case TYPE_STRING:	return std::string(*this) > std::string(value); 
	case TYPE_UINT:		return uint32(*this) > uint32(value);
	case TYPE_CHAR:		return char(*this) > char(value);
	default: return false;
	}
}

bool Value::operator<( const Value& value )
{
	return !(*this > value);
}

bool Value::operator!=( const Value& value )
{
	return !(*this == value);
}

bool Value::operator==( const Value& value )
{
	if(value.size() != this->size()) 
		return false; 
	if(value.GetType() != this->GetType()) 
		return false;
	switch(this->GetType()) 
	{
	case TYPE_INT:		return int32(*this) == int32(value); 
	case TYPE_STRING:	return std::string(*this) == std::string(value); 
	case TYPE_UINT:		return uint32(*this) == uint32(value);
	case TYPE_CHAR:		return char(*this) == char(value);
	default: return false;
	}
}
std::ostream& operator<<( std::ostream& os, const Value& value )
{
	const std::list<Value::Data*>& m_data = value.m_data;

	if(!m_data.size()) return os;
	if(!m_data.front()->m_data) return os;


	for (std::list<Value::Data*>::const_iterator i = m_data.begin(); i != m_data.end(); i++) {

		switch((*i)->m_type) {
			case Value::TYPE_STRING:	os << *static_cast<std::string*>((*i)->m_data); break;
			case Value::TYPE_INT:		os << *static_cast<int*>		((*i)->m_data); break;
			case Value::TYPE_UINT:		os << *static_cast<uint32*>		((*i)->m_data); break;
			case Value::TYPE_CHAR:		os << *static_cast<char*>		((*i)->m_data); break; 
			default: break;
		}
		std::list<Value::Data*>::const_iterator itr = i++; 
		if(itr != m_data.end()) {
			os << ", ";
		}
	}

	return os;
}



Value::Data::~Data()
{
	if(m_data){
		switch(m_type) {
					case TYPE_STRING: delete static_cast<std::string*>(m_data); break;
					case TYPE_INT:	  delete static_cast<int*>(m_data); break;
					case TYPE_UINT:	  delete static_cast<uint32*>(m_data); break;
					case TYPE_CHAR:	  delete static_cast<char*>(m_data); break;
					default: break;
		}
	}
}
